#ifndef __UM_SINK_H__
#define __UM_SINK_H__

#include "um_basic_types.h"
#include "umapi_os.h"
#include "umapi_socket.h"
#include "umapi_os_list.h"
#include "stddef.h"
#include <unistd.h>
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavformat/version.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avstring.h"
#include "epollTools.h"
#include "serverConfig.h"

typedef struct
{
	const UM_CHAR* protocol;
	UM_S32 (*open)(UM_VOID *pSink, UM_CHAR *outUrl);
	UM_S32 (*destroy)(UM_VOID *pSink);
	UM_S32 (*start)(UM_VOID *pSink);
	UM_S32 (*stop)(UM_VOID *pSink);
	UM_S32 (*trace)(UM_VOID *pSink);
	UM_S32 (*attachSource)(UM_VOID *pSink, UM_VOID *pSource);
	UM_S32 (*writePacket)(UM_VOID *pSink, AVPacket *pkt);
	UM_S32 priSize;
	UM_VOID *pri;
	struct umapi_list_head head;
}S_SINK;

typedef struct
{
	UM_VOID* (*add)(UM_VOID *s, UM_CHAR *path);
	UM_S32 (*del)(UM_VOID *s, UM_VOID* n);
	UM_S32 (*start)(UM_VOID *s, UM_VOID* n);
	UM_S32 (*stop)(UM_VOID *s, UM_VOID* n);
	UM_S32 (*write)(UM_VOID *s, UM_VOID* n, AVPacket *pkt);
}S_SINK_WORK;



#define COPYAV(src,dst) do{ \
		AVOutputFormat* fmt = dst->oformat; \
		UM_S32 i = 0, res=0;  \
		AVStream *out_stream = NULL; \
		AVStream *in_stream = NULL; \
		AVCodecContext *dec_ctx, *enc_ctx; \
		AVCodec *encoder; \
		for (; i < src->nb_streams; i++) \
		{ \
			in_stream = src->streams[i];	\
			out_stream = avformat_new_stream(dst, avcodec_find_decoder(in_stream->codec->codec_id)); \
			if (!out_stream) \
			{ \
				return UM_FAILURE; \
			} \
			res = avcodec_parameters_copy(out_stream->codecpar,in_stream->codecpar); \
			if (res < 0) \
			{ \
				return UM_FAILURE; \
			} \
			if(in_stream->codec->codec_id == AV_CODEC_ID_AAC){ \
				fillextradata(out_stream, in_stream); \
			}\
		} \
	}while(0)
	

#define SINKFUNS(s_s, findServer) \
static UM_S32 open(UM_VOID *pSink, UM_CHAR *outUrl) \
{	\
	s_s *c = GETSINKCONTEXT(s_s*, pSink); \
	decUrl(c->host, &c->port, c->path, outUrl); \
	c->server = findServer(c); \
	if(!c->server) \
		return UM_FAILURE; \
	c->n = c->server->workCall.add(c->server, c->path); \
	return UM_SUCCESS;	\
} \
static UM_S32 destroy(UM_VOID *pSink) \
{ \
	s_s *c = GETSINKCONTEXT(s_s*, pSink); \
	c->server->workCall.del(c->server, c->n); \
	umapi_free(c); \
	return UM_SUCCESS; \
} \
static UM_S32 start(UM_VOID *pSink) \
{ \
	s_s *c = GETSINKCONTEXT(s_s*, pSink); \
	c->server->workCall.start(c->server, c->n); \
	return UM_SUCCESS; \
}\
static UM_S32 stop(UM_VOID *pSink) \
{\
	s_s *c = GETSINKCONTEXT(s_s*, pSink);\
	c->server->workCall.stop(c->server, c->n);\
	return UM_SUCCESS;\
}\
static UM_S32 writePacket(UM_VOID *pSink, AVPacket *pkt)\
{\
	s_s *c = GETSINKCONTEXT(s_s*, pSink);\
	c->server->workCall.write(c->server, c->n, pkt);\
	return UM_SUCCESS;\
}


#define INITSERVER(ss,hh,ii) \
static struct umapi_list_head ss; \
static UM_HANDLE hh; \
static UM_BOOL ii = UM_FALSE; \
static UM_VOID initServers() \
{ \
	if(ii) \
		return ; \
	umapi_os_mutex_create(UM_NULL,UM_OS_MUTEX_ATTR_TIMED_NP,&hh);\
	umapi_list_create(&ss);\
	ii = UM_TRUE;\
	return ;\
}


extern S_SINK httpSink;
extern S_SINK rtspSink;
extern S_SINK hlsSink;
extern S_SINK rtsp2Sink;

extern S_SYSTEM_DATA gSystemData;

#define GETSINKCONTEXT(t, p) (t)(((S_SINK *)p)->pri)
#define DEBUG(fmt, arg...) printf("[%s.%d]"fmt"\n",__FUNCTION__,__LINE__,##arg)

#endif
